#pragma once

#include <string>
#include <strings.h>

/*网络必要的头文件*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*日志头文件*/
#include "logMessage.hpp"

#include <unistd.h>

namespace client
{
    using namespace std;
    class tcpClient
    {
    public:
        tcpClient(const string &serverIp, const uint16_t &serverPort)
            : _socketFd(-1), _serverIp(serverIp), _serverPort(serverPort)
        {
            _socketFd = socket(AF_INET, SOCK_STREAM, 0);
            if (_socketFd == -1)
            { /*客户端通常不需要打印日志*/
                cerr << "socket failed..." << endl;
                exit(-1);
            }
        }

        void start()
        {
            struct sockaddr_in server = getSockaddr_in();
            int n = connect(_socketFd, (struct sockaddr *)&server, sizeof(server));
            if (n == -1)
            {
                cerr << "connect failed..." << endl;
                exit(-2);
            }
            else
            {
                while (true)
                {
                    cout << "Please Say# ";
                    string message;
                    getline(cin, message);
                    write(_socketFd, message.c_str(), message.size());

                    char buffer[1024];
                    int n = read(_socketFd, buffer, sizeof(buffer) - 1);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        cout << "server sent back: " << buffer << endl;
                    }
                    else
                    { /*服务端退出*/
                        cerr << "server quit!" << endl;
                        break;
                    }
                }
            }
        }

    private:
        /*客户端不关心自己的IP和端口号
         *主要关心服务端的IP和端口号*/
        string _serverIp;
        uint16_t _serverPort;
        int _socketFd;

        /*将用于网络通信的结构体的设置封装成模块
         *由于编译器优化实际上只发生一次拷贝构造*/
        struct sockaddr_in getSockaddr_in()
        {
            struct sockaddr_in server;
            bzero((void *)&server, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_serverPort);
            server.sin_addr.s_addr = inet_addr(_serverIp.c_str());
            return server;
        }
    };
} /*namespace client ends here*/